const express = require('express');
const router = express.Router();
const logHandler = require('../component/logHandler');
const request = require('request');
const Iconv = require('iconv-lite');
const { changeTwoDecimal_f, formatDate } = require('../component/util');
const ApiResult = require('../model/ApiResult');
const httpStatusCode = require("httpstatuscode").httpStatusCode;
const mongodbManager = require('../manager/mongodbManager');
const { Collection, Date_Format } = require('../component/constant');
const ObjectId = require('mongodb').ObjectId;
const validator = require('../component/validator');
const redisManager = require('../manager/redisManager');
const RedisConfig = require('../config/RedisConfig');
const {MongodbUpdator} = require('../model/MongodbUpdator');
const {MongodbSetter} = require('../model/MongodbSetter');

/**
 * @api {post} /api/find/stockTransactionDataList
 * @apiDescription 根据股票的code列表，查找股票的实时交易记录
 * @apiName /api/find/stockTransactionDataList
 * @apiGroup stockTransactionData
 * @apiSuccess {json} ApiResult对象
 * @apiSuccessExample {json} 例如：
 *  {
 *      "success": true,
        "code": 200,
        "message": "查询成功",
        "data": [
            {
                "code": "688093",
                "name": "N世华",
                "newestPrice": "28.470",
                "todayOpenPrice": "30.200",
                "yestodayPrice": "17.550",
                "highestPrice": "32.000",
                "lowestPrice": "28.080",
                "upDownPrice": "10.92",
                "upDownPercentage": "62.22"
            },
            {
                "code": "003011",
                "name": "N海象",
                "newestPrice": "55.680",
                "todayOpenPrice": "46.400",
                "yestodayPrice": "38.670",
                "highestPrice": "55.680",
                "lowestPrice": "46.400",
                "upDownPrice": "17.01",
                "upDownPercentage": "43.99"
            }
        ]
    }
 * @apiSampleRequest http://localhost:3000/api/find/stockTransactionDataList
 * @apiVersion 1.0.0
 */
router.post('/api/find/stockTransactionDataList', async (req, res, next) => {

  // 调用第三方接口，获取股票的实时交易数据
  const readStockTransactionData = function (url) {
    return new Promise((resolve, reject) => {
      request({ url: url, encoding: null }, function (error, response, body) {
        if (!error && response.statusCode == httpStatusCode.OK) {
          let data = Iconv.decode(body, 'gb2312').toString();
          let paramArray = data.split('=');
          // 代码
          let code = paramArray[0].split('_')[2].substring(2, paramArray[0].split('_')[2].length);
          let dataArray = paramArray[1].substring(1, paramArray[1].length - 3).split(',');
          // 名称
          let name = dataArray[0];
          // 最新价
          let newestPrice = dataArray[3];
          // 今开
          let todayOpenPrice = dataArray[1];
          // 昨收
          let yestodayPrice = dataArray[2];
          // 最高价
          let highestPrice = dataArray[4];
          // 最低价
          let lowestPrice = dataArray[5];
          // 涨跌额
          let upDownPrice = changeTwoDecimal_f(newestPrice - yestodayPrice);
          // 涨跌幅
          let upDownPercentage = changeTwoDecimal_f(upDownPrice / yestodayPrice * 100);
          // 股票交易信息对象
          stockTransactionData = {
            code, name, newestPrice, todayOpenPrice, yestodayPrice, highestPrice,
            lowestPrice, upDownPrice, upDownPercentage
          };
          // logHandler.info(stockTransactionData);
          resolve(stockTransactionData);
        }
      });
    });
  };

  // 首先判断传进来的参数（code）是否合法（存在这支股票），然后调用第三方接口获取实时交易数据
  let stockTransactionDataList = [];
  async function getStockTransactionDataList(stockCodeList) {
    for (let i in stockCodeList) {
      let stockCode = stockCodeList[i];
      await mongodbManager.findDocument(Collection.STOCK_INFO, { code: stockCode }).then(async (result) => {
        if (null != result) {
          let urlParam = result[0].url_param;
          let url = 'http://hq.sinajs.cn/list=' + urlParam;
          let p = await readStockTransactionData(url).then((_result) => {
            stockTransactionDataList.push(_result);
          });
        }
      });
    }
  }

  // 调用第三方接口，获取股票的实时交易数据
  let stockCodeList = req.body.stockCodeList;
  let userId = req.body.userId;
  await getStockTransactionDataList(stockCodeList);

  // 添加price_up、price_down、change_range字段
  if (stockTransactionDataList) {
    for (let i = 0; i < stockTransactionDataList.length; i++) {
      let stockTransactionData = stockTransactionDataList[i];
      await getRemindTime(userId, stockTransactionData);
    }
  }
  async function getRemindTime(userId, stockTransactionData) {
    if (userId && stockTransactionData) {
      await mongodbManager.findDocument(Collection.REL_USER_STOCK_INFO,
        { user_id: ObjectId(userId), code: stockTransactionData.code }).then(async (result) => {
          if (null != result) {
            // logHandler.info(result[0]);
            stockTransactionData.priceUp = result[0].price_up;
            stockTransactionData.priceDown = result[0].price_down;
            stockTransactionData.changeRange = result[0].change_range;
          }
        });
    }
  }

  // 接口返回值
  let apiResult = new ApiResult(true, httpStatusCode.OK, '查询成功', stockTransactionDataList);
  res.send(JSON.stringify(apiResult));
});

/**
 * @api {post} /api/subscribe/stock
 * @apiDescription 根据股票的代码或名称，订阅股票
 * @apiName /api/find/stockTransactionDataList
 * @apiGroup stockTransactionData
 * @apiSuccess {json} ApiResult对象
 * @apiSuccessExample {json} 例如：
 *  {
      success: true,
      code: 200,
      message: '订阅成功',
      data: {
        code: '000005',
        name: '世纪星源',
        newestPrice: '2.610',
        todayOpenPrice: '2.640',
        yestodayPrice: '2.650',
        highestPrice: '2.640',
        lowestPrice: '2.600',
        upDownPrice: '-0.04',
        upDownPercentage: '-1.51'
      }
    }
 * @apiSampleRequest http://localhost:3000/api/subscribe/stock
 * @apiVersion 1.0.0
 */
router.post('/api/subscribe/stock', async (req, res, next) => {

  // 根据股票代码或股票名称来判断这支股票是否存在，如果不存在则直接返回
  let result = await validator.validateCodeOrName(req.body.stockInfo);
  if (!result) {
    const errorMessage = `参数【${req.body.stockInfo}】有错误，没有查到这只股票`;
    logHandler.warn(errorMessage);
    let apiResult = new ApiResult(false, httpStatusCode.BadRequest, errorMessage, null);
    res.send(JSON.stringify(apiResult));
    return;
  }

  // 如果已经订阅了这支股票，则直接返回
  let hasSubscribe = false;
  let _result = result;
  await mongodbManager.findDocument(Collection.REL_USER_STOCK_INFO, { stock_info_id: result.stockInfo._id }).then(async (_res) => {
    if (_res) {
      const errorMessage = `股票【${_result.stockInfo.name}】已经订阅!`;
      logHandler.warn(errorMessage);
      let apiResult = new ApiResult(false, httpStatusCode.BadRequest, errorMessage, null);
      res.send(JSON.stringify(apiResult));
      hasSubscribe = true;
    }
  });
  if (hasSubscribe) {
    return;
  }

  // 获取订阅股票的实时交易记录
  let url = 'http://hq.sinajs.cn/list=' + result.urlParam;
  new Promise((resolve, reject) => {
    request({ url: url, encoding: null }, function (error, response, body) {
      if (!error && response.statusCode == httpStatusCode.OK) {
        let data = Iconv.decode(body, 'gb2312').toString();
        // 判断是否查到了股票的交易数据，如果没有这支股票的交易数据，则直接返回。
        if (data == 'var hq_str_null="";\n') {
          reject('没有这支股票');
        }
        let paramArray = data.split('=');
        // 代码
        let code = paramArray[0].split('_')[2].substring(2, paramArray[0].split('_')[2].length);
        let dataArray = paramArray[1].substring(1, paramArray[1].length - 3).split(',');
        // 名称
        let name = dataArray[0];
        // 最新价
        let newestPrice = dataArray[3];
        // 今开
        let todayOpenPrice = dataArray[1];
        // 昨收
        let yestodayPrice = dataArray[2];
        // 最高价
        let highestPrice = dataArray[4];
        // 最低价
        let lowestPrice = dataArray[5];
        // 涨跌额
        let upDownPrice = changeTwoDecimal_f(newestPrice - yestodayPrice);
        // 涨跌幅
        let upDownPercentage = changeTwoDecimal_f(upDownPrice / yestodayPrice * 100);
        // 股票交易信息对象
        stockTransactionData = {
          code, name, newestPrice, todayOpenPrice, yestodayPrice, highestPrice,
          lowestPrice, upDownPrice, upDownPercentage
        };
        logHandler.info(stockTransactionData);
        resolve(stockTransactionData);
      }
    });
  }).then(
    (result) => {
      let _result = result;
      let user = JSON.parse(req.header('user'));
      let date = new Date();
      let subscriptionTime = formatDate(date, Date_Format.YYYY_MM_DD_HH_MM_SS);
      mongodbManager.findDocument(Collection.STOCK_INFO, { code: result.code }).then(async (result) => {
        if (null != result) {
          let stockInfoId = result[0]._id;
          let document = {
            'user_id': ObjectId(user.userId),
            'stock_info_id': stockInfoId,
            'code': result[0].code,
            'subscription_time': subscriptionTime,
            'price_up': null,
            'price_down': null,
            'change_range': null,
          };
          mongodbManager.insertDocument(Collection.REL_USER_STOCK_INFO, document);

          // 返回订阅股票的实时交易记录
          let apiResult = new ApiResult(true, httpStatusCode.OK, '订阅成功', _result);
          res.send(JSON.stringify(apiResult));
          res.end();
        }
      });
    },
    (errorMessage) => {
      // 如果没有这支股票的交易数据，则返回相应的对象。
      logHandler.warn(errorMessage);
      let apiResult = new ApiResult(false, httpStatusCode.BadRequest, errorMessage, null);
      res.send(JSON.stringify(apiResult));
      res.end();
    }
  );
});

/**
 * @api {post} /api/delete/subscription
 * @apiDescription 根据股票的代码，删除股票订阅。注意：返回值只是说明执行了删除操作，但并不代表都执行成功。
 * @apiName /api/delete/subscription
 * @apiGroup stockTransactionData
 * @apiSuccess {json} ApiResult对象
 * @apiSuccessExample {json} 例如：
 *  {
 *    success: true, 
 *    code: 200, 
 *    message: "已经执行了删除rel_user_stock_info表中记录的操作", 
 *    data: null
 * }
 * @apiSampleRequest http://localhost:3000/api/delete/subscription
 * @apiVersion 1.0.0
 */
router.post('/api/delete/subscription', async (request, response, next) => {

  // 验证header中的user参数
  if (!request.headers.user) {
    const errorMessage = `header中的参数【user】有错误`;
    logHandler.warn(errorMessage);
    let apiResult = new ApiResult(false, httpStatusCode.BadRequest, errorMessage, null);
    res.send(JSON.stringify(apiResult));
    return;
  }

  // 验证deleteSubscriptionList参数
  if (!request.body.deleteSubscriptionList || request.body.deleteSubscriptionList.length == 0) {
    const errorMessage = `参数【deleteSubscriptionList】有错误`;
    logHandler.warn(errorMessage);
    let apiResult = new ApiResult(false, httpStatusCode.BadRequest, errorMessage, null);
    res.send(JSON.stringify(apiResult));
    return;
  }

  // 解析参数
  let user = JSON.parse(request.headers.user);
  let deleteSubscriptionList = request.body.deleteSubscriptionList;

  // 删除rel_user_stock_info表中的记录
  for (let i = 0; i < deleteSubscriptionList.length; i++) {
    let code = deleteSubscriptionList[i];
    await mongodbManager.deleteDocument(Collection.REL_USER_STOCK_INFO,
      { user_id: ObjectId(user.userId), code: code }).then(async (result) => {
        if (null != result) {
          logHandler.info(`rel_user_stock_info表中，user_id为${user.userId}，code为${code}的记录已被删除`);
        } else {
          logHandler.warn(`删除rel_user_stock_info表中，user_id为${user.userId}，code为${code}的记录失败`);
        }
      });
  }

  // 返回值
  const message = `已经执行了删除rel_user_stock_info表中记录的操作`;
  logHandler.warn(message);
  let apiResult = new ApiResult(true, httpStatusCode.OK, message, null);
  response.send(JSON.stringify(apiResult));
  return;
});

/**
 * @api {get} /api/diagnose/:codeOrName
 * @apiDescription 根据股票的代码或名称，诊断股票
 * @apiName /api/diagnose/:codeOrName
 * @apiGroup stockTransactionData
 * @apiSuccess {json} ApiResult对象
 * @apiSuccessExample {json} 例如：
 *  {
      code: 200
      data: "{"ID_":17480685,"DATE_":"2020-11-01T16:00:00.000Z","CODE_":"002227","MA_TREND":0,"MACD_TREND":1,"KD_TREND":1}"
      message: "股票【002227】的诊断数据为{"ID_":17480685,"DATE_":"2020-11-01T16:00:00.000Z","CODE_":"002227","MA_TREND":0,"MACD_TREND":1,"KD_TREND":1}"
      success: true
    }
 * @apiSampleRequest http://localhost:3000/api/diagnose/:codeOrName
 * @apiVersion 1.0.0
 */
router.get('/api/diagnose/:codeOrName', async (req, res, next) => {
  let codeOrName = req.params.codeOrName;
  logHandler.info(`将要诊断的股票为${codeOrName}`);

  // 根据股票代码或股票名称，查询stock_info集合，判断这支股票是否存在，如果不存在则直接返回；
  let result = await validator.validateCodeOrName(codeOrName);
  if (!result) {
    const errorMessage = `参数【${codeOrName}】有错误，没有查到这只股票`;
    logHandler.warn(errorMessage);
    let apiResult = new ApiResult(false, httpStatusCode.BadRequest, errorMessage, null);
    res.send(JSON.stringify(apiResult));
    return;

  } else {
    // 从redis中获取最大日期
    let dateString = await redisManager.get(RedisConfig.KEY_OF_MAX_DATE_OF_MDL_STOCK_ANALYSIS_IN_REDIS).then((result) => {
      return result;
    }, (err) => {
      logHandler.error(err);
      return null;
    });

    // 从redis中获取数据
    let mdlStockAnalysis = await redisManager.hget(dateString, result.stockInfo.code).then((result) => {
      return result;
    }, (err) => {
      logHandler.error(err);
      return err;
    });

    // 返回结果
    const message = `股票【${codeOrName}】的诊断数据为${mdlStockAnalysis}`;
    logHandler.info(message);
    let apiResult = new ApiResult(true, httpStatusCode.OK, message, mdlStockAnalysis);
    res.send(JSON.stringify(apiResult));
    return;
  }
});

router.post('/api/remind/stockPrice', async (request, response, next) => {
  // 接口参数
  let userId = request.body.userId;
  let code = request.body.stockPriceReminderVo.stockCode;
  let stockPriceUp = request.body.stockPriceReminderVo.stockPriceUp;
  let stockPriceDown = request.body.stockPriceReminderVo.stockPriceDown;
  let changeRange = request.body.stockPriceReminderVo.changeRange;
  let mongodbSetter = new MongodbSetter(stockPriceUp, stockPriceDown, changeRange);
  let mongodbUpdator = new MongodbUpdator({user_id: new ObjectId(userId), code}, mongodbSetter, {safe: true});

  // 修改rel_user_stock_info表中的记录
  await mongodbManager.updateDocument(Collection.REL_USER_STOCK_INFO, mongodbUpdator).then(async (result) => {
    if (null != result) {
      const message = `rel_user_stock_info集合中，user_id为${userId}，code为${code}的记录的股价提醒信息已被更新`;

      logHandler.info(message);

      let apiResult = new ApiResult(true, httpStatusCode.OK, message, null);
      response.send(JSON.stringify(apiResult));

      return;
    } else {
      const message = `更新rel_user_stock_info集合中，user_id为${userId}，code为${code}的记录失败`;

      logHandler.warn(message);
      
      let apiResult = new ApiResult(false, httpStatusCode.InternalServerError, message, null);
      response.send(JSON.stringify(apiResult));

      return;
    }
  });
});

module.exports = router;
